/**
 * 
 */
package com.newture.lxz.util;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author xiao.hu
 * 雪花算法基于秒的简化版
 */
public class SNKit {
	private static final AtomicInteger atomicInteger = new AtomicInteger(0);
	private static long lastTimeSecond = 0L;
	private static int workerId = 0; /*机器id*/

	public static synchronized String nextId() {
		long timeSecond = nowDateSecond();

        //如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时候应当抛出异常
        if (timeSecond < lastTimeSecond) {
            throw new RuntimeException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d seconds", lastTimeSecond - timeSecond));
        }

        //如果是同一时间生成的，则进行毫秒内序列
        if (lastTimeSecond == timeSecond) {
        	atomicInteger.incrementAndGet();
            //毫秒内序列溢出
            if (atomicInteger.intValue() > 99) { /*与fixedDigits(2, atomicInteger.intValue())配合*/
                //阻塞到下一个毫秒,获得新的时间戳
            	timeSecond = tilNextMillis(lastTimeSecond);
            	atomicInteger.set(0);
            }
        }
        //时间戳改变，毫秒内序列重置
        else {
        	atomicInteger.set(0);
        }

        //上次生成ID的时间截
        lastTimeSecond = timeSecond;
		return nowDateTimeStr() + fixedDigits(2, workerId) + fixedDigits(2, atomicInteger.intValue());
	}
	
	 /**
     * 阻塞到下一个毫秒，直到获得新的时间戳
     * @param lastTimestamp 上次生成ID的时间截
     * @return 当前时间戳
     */
    private static long tilNextMillis(long lastTimestamp) {
        long seconds = nowDateSecond();
        while (seconds <= lastTimeSecond) {
        	seconds = nowDateSecond();
        }
        return seconds;
    }
	
	/**
	 * 获得当天的日期的字符串表示
	 * eg. 20190918
	 * @return
	 */
	public static String nowDayStr() {
		LocalDate now = LocalDate.now();
		String nowDayStr = now.toString().replace("-", "");
		return nowDayStr;
	}
	
	/**
	 * 获得当天完整时间日期的格式化输出
	 * eg. 20190918123201
	 * @return
	 */
	public static String nowDateTimeStr() {
		LocalDateTime now = LocalDateTime.now();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
		return now.format(formatter);
	}
	
	/**
	 * 方法将此日期时间转换为1970-01-01T00:00:00Z的纪元的秒数
	 * @return
	 */
	public static long nowDateSecond() {
		return LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
	}
	
	/**
	 * 数值转固定长度的字符串，不足位就补0
	 * @param fixedSize
	 * @param number
	 * @return
	 */
	public static String fixedDigits(int fixedSize, int number) {
		String numStr = Integer.toString(number);
		if(numStr.length() > fixedSize) {
			throw new IllegalArgumentException("number bit width is too long");
		}
		return String.format("%0" + fixedSize + "d", number);
	}
	
	public static void main(String[] args) {
		for(int i = 0; i < 1000; i++) {
			System.out.println(SNKit.nextId());
		}
		/*System.out.println(SNKit.nowDateSecond());
		System.out.println(SNKit.fixedDigits(3, 123));*/
	}
}
